// ## 2023/5/18 #铃# 修复AI会操控玩家府的Bug ##
// ## 2023/5/09 #铃# AI府濒临陷落时会携带几乎所有的资源出逃,并且播放运输动画 ##
// ## 2023/3/19 #铃# 結合新的內政系統设计了AI府资源调度 ##

namespace AI府资源调度_AI
{

	// ================ CUSTOMIZE ================
	const bool 显示AI运输 = false;
	// ===========================================

	class Main
	{
		pk::building @building_;

		Main()
		{
			pk::bind(109, pk::trigger109_t(onNew_Season));
			pk::bind(163, pk::trigger163_t(beforerkillbuilding));
			add_menu();
		}

		void add_menu()
		{
			pk::menu_item menu_item;
			menu_item.menu = 0;
			menu_item.pos = 0;
			// menu_item.shortcut = shortcut;
			menu_item.init = pk::building_menu_item_init_t(init);
			menu_item.is_visible = pk::menu_item_is_visible_t(isVisible);
			menu_item.is_enabled = pk::menu_item_is_enabled_t(isEnabled);
			menu_item.get_image_id = pk::menu_item_get_image_id_t(get_image_id);
			menu_item.get_text = pk::menu_item_get_text_t(getText);
			menu_item.get_desc = pk::menu_item_get_desc_t(getDesc);
			menu_item.handler = pk::menu_item_handler_t(handler);
			pk::add_menu_item(menu_item);
		}

		void onNew_Season()
		{
			for (int i = 0; i < ch::get_spec_end(); ++i)
			{
				pk::point pos = ch::get_spec_pos(i);
				pk::building @building = pk::get_building(pos);

				// pk::trace(pk::format("城市id：{},城市名:{},府:{},spec_t.troops:{}", city_id, pk::decode(pk::get_name(pk::get_building(city_id))), src_name,spec_t.troops));

				// pk::trace(pk::format("i :{},x :{},y :{},building.get_id :{}", i, pos.x, pos.y, building.get_id()));

				if (!pk::is_alive(building))
					continue;

				pk::force @force = pk::get_force(building.get_force_id());

				if (!pk::is_alive(force))
					continue;

				int spec_id = ch::to_spec_id(building.get_id());
				auto spec_t = ch::get_spec_p(i);
				// pk::trace(pk::format("城市名:{},府:{},spec_t.troops:{}",  pk::decode(pk::get_name(pk::get_building(pk::get_building_id(building.pos)))), ch::get_spec_name(spec_id),spec_t.troops));

				// pk::trace(pk::format("spec_id :{}",spec_id));

				if (ch::get_spec_p(i).person == -1)
					continue;

				if (building.get_force_id() != force.get_id())
					continue;

				int city_id = pk::get_building_id(building.pos);
				if (pk::get_building(city_id).get_force_id() != force.get_id())
					continue;

				// 玩家控制的军团除外
				pk::building @location_city = pk::get_building(city_id);
				if (pk::is_player_controlled(location_city) and !ch::get_spec_p(i).get_spec_set(SPEC_CAN_TRANSPORT)) // if (pk::is_player_controlled(building))
					continue;

				// 玩家控制的兵临城下时也不做操作
				if (pk::enemies_around(building) and building.is_player())
					continue;

				auto base_t = ch::get_base_p(city_id);
				auto building_p = ch::get_baseIA(city_id);
				pk::building @city = pk::get_building(city_id);
				int person_id = ch::get_spec_p(i).person;

				spec_id = ch::to_spec_id(building.get_id());

				if (!ch::is_valid_spec_id(spec_id))
					continue;

				string src_name = ch::get_spec_name(spec_id);

				bool 完全包围 = (府一格内敌方部队(building) == 府一格内有效地形(building));

				// pk::trace(pk::format("城市id：{},城市名:{},府:{},spec_t.troops:{}", city_id, pk::decode(pk::get_name(pk::get_building(city_id))), src_name,spec_t.troops));

				// 府兵资源转移

				if (((spec_t.troops > 5000 and spec_t.troops > int(pk::get_troops(city) * 0.35)) or spec_t.troops > 10000) and pk::get_troops(city) < pk::get_max_troops(city) - 10000 and !pk::enemies_around(city) and !pk::enemies_around(building))
				{

					int reduce = int(spec_t.troops * 0.3);

					spec_t.add_troops(-reduce);
					ch::add_troops(city, reduce, false);

					if (pk::is_in_screen(pos))
						府兵运输队(building, city, person_id, reduce, 0, 0);

					pk::combat_text(-reduce, 1, pos);
					pk::combat_text(reduce, 1, city.pos);

					string t = pk::format("\x1b[2x{}向{}\x1b[0x自动调度士兵\x1b[1x{}人\x1b[0x", src_name, pk::decode(pk::get_name(city)), reduce); 

					if (building.is_player() or 显示AI运输)
						pk::history_log(building.pos, pk::get_force(building.get_force_id()).color, pk::encode(t));
					// pk::trace(pk::format("常规转移城市id：{},城市名:{},府名:{},兵力:{},reduce:{}", city_id ,pk::decode(pk::get_name(pk::get_building(city_id))),src_name,pk::get_troops(city),reduce));
				}

				// 府兵多余资金转移
				if ((spec_t.gold > 5000 and (spec_t.gold > int(pk::get_gold(city) * 0.5) or spec_t.gold > 10000)) and pk::get_gold(building) < pk::get_max_gold(city) - 10000 and !pk::enemies_around(city) and !pk::enemies_around(building))
				{

					int reduce = int(spec_t.gold * 0.3);
					spec_t.add_gold(-reduce);
					pk::add_gold(city, reduce, false);

					if (pk::is_in_screen(pos))
						府兵运输队(building, city, person_id, 1000, reduce, 0);

					pk::combat_text(-reduce, 3, pos);
					pk::combat_text(reduce, 3, city.pos);

					string t = pk::format("\x1b[2x{}向{}\x1b[0x自动调度资金\x1b[1x{}\x1b[0x", src_name, pk::decode(pk::get_name(city)), reduce); 
					if (building.is_player() or 显示AI运输)
						pk::history_log(building.pos, pk::get_force(building.get_force_id()).color, pk::encode(t));
				}

				// 府兵多余兵粮转移
				if ((spec_t.food > 20000 and (spec_t.food > int(pk::get_food(city) * 0.5) or spec_t.food > 50000)) and pk::get_food(building) < pk::get_max_food(city) - 20000 and !pk::enemies_around(city) and !pk::enemies_around(building))
				{
					int reduce = int(spec_t.food * 0.3);

					spec_t.add_food(-reduce);
					pk::add_food(city, reduce, false);

					if (pk::is_in_screen(pos))
						府兵运输队(building, city, person_id, 1000, 0, reduce);

					pk::combat_text(-reduce, 4, pos);
					pk::combat_text(reduce, 4, city.pos);

					string t = pk::format("\x1b[2x{}向{}\x1b[0x自动调度兵粮\x1b[1x{}\x1b[0x", src_name, pk::decode(pk::get_name(city)), reduce); 
							if (building.is_player() or 显示AI运输)
						pk::history_log(building.pos, pk::get_force(building.get_force_id()).color, pk::encode(t));
				}

				int 损耗 = 0;
				损耗 = 府一格内敌方部队(building) * 2 + ai::base_around_enemy_troops[city.get_id()] / 3000;
				损耗 = pk::clamp(损耗, 0, 99);

				// 城市紧急状态下府兵资源转移,如果府被包围则无法完成.
				// 兵力差距足够大才会调度,防止玩家恶意利用.
				// 每次调度数百到1000多人左右,缓慢调度以免让玩家觉得困惑.
				// 调度量和兵力差距直接相关.
				// 损耗和府被围困程度.城市被围困程度有关.
				if (!building.is_player() and (spec_t.troops > 2000 and ai::base_around_enemy_troops[city.get_id()] > 3000 and ai::base_around_enemy_troops[city.get_id()] > int(pk::get_troops(city) * 0.8) and pk::get_troops(city) < 50000 and (pk::get_troops(city) < 20000 or city.hp - int(0.8 * (pk::get_max_hp(city))) < 0)))
				{
					if (完全包围)
					{
						string t = pk::format("\x1b[2x{}\x1b[0x危在旦夕,\x1b[2x{}\x1b[0x的部队救援\x1b[2x{},\x1b[0x但由于\x1b[2x{}\x1b[0x自身被完全包围而无法救援", pk::decode(pk::get_name(city)), src_name, pk::decode(pk::get_name(city)), src_name);
						pk::history_log(building.pos, pk::get_force(building.get_force_id()).color, pk::encode(t));
						return;
					}

					int reduce = int((spec_t.troops - 1500) * 1.0);
					pk::clamp(reduce, 0, spec_t.troops);

					spec_t.add_troops(-reduce);
					ch::add_troops(city, int(reduce * (1 - 损耗 / 100.0)), false);

					if (pk::is_in_screen(pos))
						府兵运输队(building, city, person_id, reduce, 0, 0);

					pk::combat_text(-reduce, 1, pos);
					pk::combat_text(int(reduce * (1 - 损耗 / 100.0)), 1, city.pos);

					string t = pk::format("\x1b[2x{}\x1b[0x危在旦夕,\x1b[2x{}\x1b[0x向\x1b[2x{}\x1b[0x支援,但受到攻城部队的攻击,最后仅有\x1b[1x{}\x1b[0x人到达\x1b[2x{}", pk::decode(pk::get_name(city)), src_name, pk::decode(pk::get_name(city)), int(reduce * (1 - 损耗 / 100.0)), pk::decode(pk::get_name(city)));
					pk::history_log(building.pos, pk::get_force(building.get_force_id()).color, pk::encode(t));
				}
			}
		}

		void beforerkillbuilding(pk::building @building, bool sound = false)
		{

			int building_id = building.get_id();
			int spec_id = ch::get_spec_id(pk::get_building(building_id));
			if (spec_id == -1)
				return;

			if (building.is_player())
				return;

			auto spec_t = ch::get_spec_p(spec_id);
			string src_name = ch::get_spec_name(ch::to_spec_id(building_id));
			if (spec_t.troops < 1000)
				return;
			int city_id = pk::get_city_id(building.pos);
			pk::building @city = pk::get_building(city_id);

			if (building.get_force_id() != city.get_force_id())
				return;
			// pk::trace(pk::format("地名：{},", 6));
			auto base_t = ch::get_base_p(city_id);
			// auto building_p = ch::get_baseIA(city_id);

			bool 完全包围 = (府一格内敌方部队(building) == 府一格内有效地形(building));

			if (完全包围)
			{
				string t = pk::format("\x1b[2x{}失陷,剩余部队试图向{}\x1b[2x\x1b[0x撤退,但突围失败,全军覆没", src_name, pk::decode(pk::get_name(city)), pk::decode(pk::get_name(city)));
				pk::history_log(building.pos, pk::get_force(building.get_force_id()).color, pk::encode(t));
				return;
			}

			// 损耗和府被围困程度.城市被围困程度有关.
			int 兵力损耗 = 10;
			兵力损耗 = (building.is_player() ? 30 : 15) + 府一格内敌方部队(building) * (building.is_player() ? 5 : 3) + (府两格内敌方兵力(building) / (building.is_player() ? 1000 : 2000));
			兵力损耗 = pk::clamp(兵力损耗, 0, 99);

			int 钱粮损耗 = pk::clamp(兵力损耗 * 2, 0, 99);

			int reduce_troops = spec_t.troops * (100 - 兵力损耗) / 100;
			int reduce_gold = spec_t.gold * (100 - 钱粮损耗) / 100;
			int reduce_food = spec_t.food * (100 - 钱粮损耗) / 100;

			spec_t.add_troops(-reduce_troops);
			ch::add_troops(city, reduce_troops, true);

			spec_t.add_gold(-reduce_gold);
			pk::add_gold(city, reduce_gold, true);

			spec_t.add_food(-reduce_food);
			pk::add_food(city, reduce_food, true);

			int person_id = spec_t.person;
			if (pk::is_in_screen(building.pos))
				府兵运输队(building, city, person_id, reduce_troops, reduce_gold, reduce_food);

			string t = pk::format("\x1b[2x{}\x1b[0x失陷,剩余部队向\x1b[2x{}\x1b[0x\x1b[0x撤退,但仅有\x1b[1x{}人\x1b[0x成功突围。", src_name, pk::decode(pk::get_name(city)), int(reduce_troops * (1 - 兵力损耗 / 100)));
			pk::history_log(building.pos, pk::get_force(building.get_force_id()).color, pk::encode(t));
			// pk::trace(pk::format("紧急转移城市id：{},城市名:{},敌方兵力:{},己方兵力:{},reduce:{}", city_id, pk::decode(pk::get_name(pk::get_building(city_id))), 城市三格内敌军兵力(city), 计算己方兵力(city), reduce));
		}

		int 府一格内敌方部队(pk::building @building)
		{

			int enemy_units = 0;

			auto range = pk::range(building.get_pos(), 1, 1);
			for (int i = 0; i < int(range.length); i++)
			{
				auto unit = pk::get_unit(range[i]);
				if (pk::is_alive(unit) and pk::is_enemy(building, unit))
				{

					enemy_units++;
					// pk::trace(pk::format("range.length：{},unit.troops:{},enemy_troops:{},enemy_unit:{}", range.length, unit.troops, enemy_troops,enemy_units));
				}
			}
			return enemy_units;
		}

		int 府两格内敌方兵力(pk::building @building)
		{
			int enemy_troops = 0;
			int enemy_units = 0;

			auto range = pk::range(building.get_pos(), 1, 2);
			for (int i = 0; i < int(range.length); i++)
			{
				auto unit = pk::get_unit(range[i]);
				if (pk::is_alive(unit) and pk::is_enemy(building, unit))
				{

					enemy_troops += unit.troops;
					// enemy_units++;
					// pk::trace(pk::format("range.length：{},unit.troops:{},enemy_troops:{},enemy_unit:{}", range.length, unit.troops, enemy_troops,enemy_units));
				}
			}
			return enemy_troops;
		}

		int 府一格内有效地形(pk::building @building)
		{
			int valid_pos_count = 0;

			auto range = pk::range(building.get_pos(), 1, 1);
			for (int i = 0; i < int(range.length); i++)
			{
				pk::hex @hex = pk::get_hex(range[i]);
				int terrain_id = hex.terrain;
				if (pk::is_enabled_terrain(terrain_id))
					valid_pos_count++;
				// pk::trace(pk::format("range.length：{},unit.troops:{},enemy_troops:{},enemy_unit:{}", range.length, unit.troops, enemy_troops,enemy_units));
			}

			return valid_pos_count;
		}

		void 府兵运输队(pk::building @building, pk::building @city, int person_id, int troops, int gold, int food)
		{
			if (!func_person_slot_available())
				return; // 沒有空余武将位则不生成

			pk::point src_pos = get_empty_pos(building.pos, 1, 2);
			pk::point dst_pos = get_empty_pos(city.pos, 2, 3);

			int distance = pk::get_distance(src_pos, dst_pos);
			if (distance > 15)
				return;

			//	break;
			pk::person @virtual_person = func_create_person(pk::get_person(person_id));
			if (!pk::is_alive(virtual_person))
			{
				pk::reset(virtual_person);
				return;
			}
			if (!pk::is_valid_pos(src_pos))
				src_pos = get_empty_pos(building.pos, 1, 2); // 生成部队前再次核实坐标有效
															 // pk::trace(pk::format("x1 :{},y1:{},x2 :{},y2 :{}", src_pos.x, src_pos.y, dst_pos.x, dst_pos.y));

			if (src_pos.x == -1)
				return;
			if (dst_pos.x == -1)
				return;

			pk::point next_pos = get_empty_pos(city.pos, 2, 3);

			pk::com_march_cmd_info cmd_draft;
			@cmd_draft.base = building;
			cmd_draft.type = 部队类型_运输;
			cmd_draft.member[0] = virtual_person.get_id();
			cmd_draft.gold = gold;
			cmd_draft.troops = troops;
			cmd_draft.food = food;
			cmd_draft.order = 部队任务_移动;
			cmd_draft.target_pos = dst_pos;
			cmd_draft.weapon_id[0] = 1;
			cmd_draft.weapon_amount[0] = 0;
			pk::unit @unit = pk::create_unit2(cmd_draft, src_pos, false);
			unit.energy = pk::get_energy(city);;

			if (next_pos != unit.pos)
			{
				// pk::trace("unit.pos.x:" + unit.pos.x + "unit.pos.y:" + unit.pos.y + "next_pos.x:" + next_pos.x + "next_pos.y:" + next_pos.y);

				if (pk::is_valid_pos(unit.pos) and pk::is_valid_pos(next_pos))
				{
					// array<pk::point> unit_path = {unit.pos, next_pos}; // 临时措施
					auto unit_path = pk::get_path(unit, unit.pos, next_pos);
					if (unit_path.length < 40 and unit_path.length > 0)
						pk::move(unit, unit_path);
				}
			}
			pk::kill(unit, true);
		}

		pk::point get_empty_pos(pk::point pos, int distance_min, int distance_max)
		{
			array<pk::point> range_pos_arr = pk::range(pos, distance_min, distance_max);
			for (int arr_index = 0; arr_index < int(range_pos_arr.length); arr_index++)
			{
				pk::point range_pos = range_pos_arr[arr_index];
				if (!pk::is_valid_pos(range_pos))
					continue;

				pk::hex @hex = pk::get_hex(range_pos);
				if (hex.has_building)
					continue;
				if (hex.has_unit)
					continue;

				int terrain_id = hex.terrain;
				if (!pk::is_valid_terrain_id(terrain_id))
					continue;
				if (!pk::is_enabled_terrain(terrain_id))
					continue;

				return range_pos;
			}

			return pk::point(-1, -1);
		}

		void kill(pk::unit @unit, int spec_id)
		{
			auto spec_t = ch::get_spec_p(spec_id);
			spec_t.add_troops(unit.troops);
			spec_t.add_gold(unit.gold);
			spec_t.add_food(unit.food);
			pk::kill(unit, true);
		}

		// 遍历所有武将，身??死亡或无的都可用来生成
		bool func_person_slot_available()
		{
			for (int person_id = 敌将_开始; person_id < 敌将_末; person_id++)
			{
				pk::person @person = pk::get_person(person_id);
				if (person.mibun == 身份_无)
					return true;
				if (person.mibun == 身份_死亡)
					return true;
			}
			return false;
		}

		// 统领武将生成
		pk::person @func_create_person(pk::person @person)
		{
			pk::person @virtual_person = pk::create_bandit(pk::get_person(武将_卫士));
			virtual_person.name_read = pk::encode("府兵");
			// if (virtual_person.mibun == 身份_在野) pk::set_mibun(virtual_person, 身份_一般);
			pk::set_district(virtual_person, person.get_district_id());

			virtual_person.base_stat[武将能力_统率] = pk::max(50, pk::min(80, int(person.base_stat[武将能力_统率] * 0.5f + ch::randint(5, 10))));
			virtual_person.base_stat[武将能力_武力] = pk::max(50, pk::min(80, int(person.base_stat[武将能力_武力] * 0.5f + ch::randint(5, 10))));
			virtual_person.base_stat[武将能力_智力] = pk::max(50, pk::min(80, int(person.base_stat[武将能力_智力] * 0.6f + ch::randint(5, 10))));
			for (int heishu_id = 兵种_枪兵; heishu_id < 兵种_末; heishu_id++)
				virtual_person.tekisei[heishu_id] = person.tekisei[heishu_id] + ch::randint(-2, 1);
			virtual_person.rank = pk::min(81, person.rank + 8);
			virtual_person.skill = 特技_突袭;
			pk::core::add_hidden_skill(virtual_person.get_id(), 特技_幸运, 1);
			virtual_person.update();

			return virtual_person;
		}

		// 菜单相关支持

		void init(pk::building @building)
		{
			@building_ = @building;
		}

		bool isVisible()
		{
			if (pk::is_campaign())
				return false;
			int spec_id = ch::to_spec_id(building_.get_id());
			if (!ch::is_valid_spec_id(spec_id))
				return false;
			int force_id = building_.get_force_id();
			if (!pk::is_valid_force_id(force_id) or pk::get_current_turn_force_id() != force_id)
				return false;
			// int spec_person = ch::get_spec_p(spec_id).person;
			// if (pk::is_valid_person_id(spec_person))
			//	return false;
			return true;
		}

		string getText()
		{
			return pk::encode("自动调度");
		}

		bool isEnabled()
		{
			return true;
		}

		int get_image_id()
		{
			int spec_id = ch::to_spec_id(building_.get_id());

			return ch::get_spec_p(spec_id).get_spec_set(SPEC_CAN_TRANSPORT) ? 1249 : 889;
		}

		string getDesc()
		{
			int spec_id = ch::to_spec_id(building_.get_id());
			string desc = ch::get_spec_p(spec_id).get_spec_set(SPEC_CAN_TRANSPORT) ? "关闭" : "开启";
			return pk::encode(pk::format("点击后{}该县城的自动调度功能", desc));
		}

		bool handler()
		{
			int spec_id = ch::to_spec_id(building_.get_id());
			ch::get_spec_p(spec_id).set_spec_set(SPEC_CAN_TRANSPORT, !ch::get_spec_p(spec_id).get_spec_set(SPEC_CAN_TRANSPORT));
			return true;
		}
	} // class
	Main main;
}